home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1993 July / InfoMagic USENET CD-ROM July 1993.ISO / sources / unix / volume11 / graphedit / part05 < prev    next >
Encoding:
Internet Message Format  |  1987-10-05  |  56.3 KB

  1. Subject:  v11i101:  Graphics editor for Suns, Part05/06
  2. Newsgroups: comp.sources.unix
  3. Sender: sources
  4. Approved: rs@uunet.UU.NET
  5.  
  6. Submitted-by: steinmetz!sbcs!nyfca1!chan (Douglas Chan)
  7. Posting-number: Volume 11, Issue 101
  8. Archive-name: graphedit/part05
  9.  
  10. # This is a shell archive.  Remove anything before this line,
  11. # then unpack it by saving it in a file and typing "sh file".
  12. #
  13. # Contents:  display.c ps.c pic.c plot.c
  14.  
  15. echo x - display.c
  16. sed 's/^@//' > "display.c" <<'@//E*O*F display.c//'
  17.  
  18. static char SccsId[] = "@(#)display.c    1.1 6/8/87  Copyright 1987 SBCS-chan";
  19.  
  20. /*****************************************************************************
  21.  
  22.           (c) Copyright 1987 
  23.  
  24.           Lap-Tak Chan
  25.           Computer Science Department
  26.           State University of New York at Stony Brook
  27.           Stony Brook, NY 11794
  28.  
  29.     This software and its documentation may be used, copied, and
  30.   distributed, provided that this legend appear in all copies and
  31.   that it is not copied or distributed for a profit.
  32.  
  33.   No representations is made about the suitability of this software
  34.   for any purpose.  It is provided "as is" with no support and no
  35.   express or implied warranty.
  36.  
  37. *****************************************************************************/
  38.  
  39. /*****************************************************************************
  40.  
  41.                              Display List
  42.                              ============
  43.  
  44.       The display list is used to maintain the data structure used to store
  45.   the segments internally.  Each segment has a display list, which
  46.   consists of its segment number, attributes, and a instruction list.
  47.   Each instruction is composed of an instruction with two arguments.
  48.  
  49.       The display list is initialized with ge_init_display.  A segment is
  50.   opened with ge_new_segment.  Output primitives are drawn with ge_graph
  51.   which will appending them to the instruction list of the segment.
  52.   ge_delete_segment will delete the segment and free the memory allocated
  53.   to the segment to the internal free lists. ge_display_list will return
  54.   a pointer to the display list of a segment.
  55.  
  56.       The display list maintains a list of segments, which is
  57.   a simple linked list of segment blocks taken from a fixed array.
  58.   Unused segment blocks in the array are linked on a free list.
  59.   Each segment block stores a pointer to the node of the object, the
  60.   current position of the segment and a instruction list of the segment.
  61.   The instruction list is stored as a circular queue of display items.
  62.   Each display item consists of a display instruction and a coordinate.
  63.  
  64.       A hash table should be used to reference the segments instead of
  65.   a search on the segment list.
  66.  
  67. *****************************************************************************/
  68.  
  69. #include "display.h"
  70. #define GE_DITEM_SIZE 50 /* number of items to obtain from calloc when
  71.                             free list is empty */
  72.  
  73. struct list ge_open[GE_OPENMAX+1]; /* array of display lists */
  74. static struct list_item *ge_dfree=0; /* free list for display instructions */
  75. static int ge_dsfree; /* free list for segment blocks */
  76. int ge_seglist; /* list of segment blocks */
  77. /* instruction to indicate close of segment */
  78. static struct list_item closeinstr;
  79.  
  80. /*****************************************************************************
  81.  
  82.       Display items have to be allocated and freed frequently.  The C
  83.   allocation routines alloc, calloc and free is not efficient.  To increase
  84.   the efficiency, a list of free display items is maintained.  Requests for
  85.   display item are allocated from the free list.  When the free list is
  86.   empty, a number of display items is obtained with calloc and linked to
  87.   the free list.
  88.  
  89.   ge_get_item will return a display item which is not in use.  It obtains
  90.   the display item from the free list.  When the free list is empty, it
  91.   get a number of display item from the system with calloc and link
  92.   them to the free list.
  93.  
  94. *****************************************************************************/
  95.  
  96. struct list_item *ge_get_item()
  97. {
  98.   struct list_item *tmp;
  99.   int count;
  100.  
  101.   /* free list is empty */
  102.   if ( ! ge_dfree ) {
  103.  
  104.     /* get space for list items */
  105.     tmp = (struct list_item *)calloc(GE_DITEM_SIZE,sizeof(struct list_item));
  106.  
  107.     /* link blocks on free list */
  108.     for(count=1;count < GE_DITEM_SIZE;count++)
  109.       tmp[count].next = &(tmp[count-1]);
  110.     ge_dfree = &(tmp[GE_DITEM_SIZE-1]);
  111.   }
  112.  
  113.   /* get item from free list */
  114.   tmp=ge_dfree;
  115.   ge_dfree=tmp->next;
  116.   return (tmp);
  117.  
  118. }
  119.  
  120. /*****************************************************************************
  121.  
  122.   ge_free_item will release a display item to the free list.
  123.  
  124. *****************************************************************************/
  125.  
  126. ge_free_item(ptr)
  127. struct list_item *ptr;
  128. {
  129.  
  130.   ptr->next = ge_dfree;
  131.   ge_dfree = ptr;
  132.  
  133. }
  134.  
  135. /*****************************************************************************
  136.  
  137.   ge_init_display initializes the display list.  It links the segment blocks
  138.   on the array to form a free list.
  139.  
  140. *****************************************************************************/
  141.  
  142. ge_init_display()
  143. {
  144.   int i;
  145.  
  146.   /* link segment blocks to form free list */
  147.   for(i=0;i<GE_OPENMAX-1;i++)
  148.     ge_open[i].next = i + 1;
  149.   ge_dsfree=1;
  150.  
  151.   /* empty segment list */
  152.   ge_seglist=0;
  153.  
  154.   closeinstr.instr=GE_CLOSE;
  155.  
  156. }
  157.  
  158. /*****************************************************************************
  159.  
  160.   ge_index searches for the display list of a segment.
  161.  
  162.   input
  163.     segno : segment number
  164.  
  165.   output
  166.     ge_index returns pointer to display list if found
  167.  
  168. *****************************************************************************/
  169.  
  170. int ge_index(segno)
  171. int segno;
  172. {
  173.   int i;
  174.  
  175.   for ( i=ge_seglist; i && ge_open[i].segno != segno; i=ge_open[i].next );
  176.   if ( ge_open[i].segno == segno ){
  177.     return (i);
  178.   }
  179.   else {
  180.     return(-1);
  181.   }
  182. }
  183.  
  184. /*****************************************************************************
  185.  
  186.   ge_new_segment is called to create a new segment.
  187.  
  188.   input
  189.     tree : pointer to node of object
  190.  
  191. *****************************************************************************/
  192.  
  193. ge_new_segment(segno)
  194. int segno;
  195. {
  196.   int pos;
  197.  
  198.   /* remove segment from free list */
  199.   pos=ge_dsfree;
  200.   ge_dsfree=ge_open[pos].next;
  201.  
  202.   /* add segment to segment list */
  203.   ge_open[pos].next = ge_seglist;
  204.   ge_seglist = pos;
  205.  
  206.   /* initialize content of list */
  207.   ge_open[pos].d_list = 0;
  208.  
  209.   ge_open[pos].segno = segno;
  210.  
  211. }
  212.  
  213. /*****************************************************************************
  214.  
  215.   ge_graph will add an output primitive to the display list of a segment.
  216.  
  217.   input
  218.     segno : segment number
  219.     instr : display instruction of output primitive (polygon, line, move, etc)
  220.     x,y : coordinate of display
  221.  
  222. *****************************************************************************/
  223.  
  224. ge_graph(segno,instr,x,y)
  225. int segno, instr;
  226. float x,y;
  227. {
  228.   int pos;
  229.   struct list_item *ptr;
  230.  
  231.   /* get display list of segment */
  232.   if ( (pos = ge_index(segno))>=0 ) {
  233.  
  234.     /* get display item */
  235.     ptr = ge_get_item();
  236.  
  237.     /* store instruction and coordinate in item */
  238.     ptr->instr=instr;
  239.     ptr->x=x;
  240.     ptr->y=y;
  241.  
  242.     /* add instruction to display list */    
  243.     if ( ge_open[pos].d_list ) {
  244.       ptr->next = ge_open[pos].d_list->next;
  245.       ge_open[pos].d_list->next = ptr;
  246.     }
  247.     else ptr->next = ptr;
  248.     ge_open[pos].d_list = ptr;
  249.  
  250.   }
  251.  
  252. } /* ge_graph */
  253.  
  254. /*****************************************************************************
  255.  
  256.   ge_delete_segment is called to delete a segment from the display list.
  257.  
  258.   input
  259.     segno : segment number
  260.  
  261. *****************************************************************************/
  262.  
  263. ge_delete_segment(segno)
  264. int segno;
  265. {
  266.   
  267.   int pos,tmpseg;
  268.   struct list_item *ptr,*tmp;
  269.  
  270.   /* search for display list of segment */
  271.   if ( pos=ge_index(segno) ) {
  272.  
  273.     /* delete segment block from list of segments */
  274.     if ( pos == ge_seglist ) {
  275.       /* segment at beginning of list */
  276.       ge_seglist = ge_open[pos].next;
  277.     }
  278.     else {
  279.       for (tmpseg=ge_seglist; (ge_open[tmpseg].next != pos);
  280.            tmpseg=ge_open[tmpseg].next) ;
  281.       ge_open[tmpseg].next = ge_open[pos].next;
  282.     }
  283.  
  284.     /* free display list of segment */
  285.     if ( ge_open[pos].d_list ) {
  286.  
  287.       /* make the display list a simple linked list */
  288.       ptr=ge_open[pos].d_list->next;
  289.       ge_open[pos].d_list->next = 0;
  290.  
  291.       /* free items along the list */
  292.       for ( ; ptr; ptr=tmp ) {
  293.         tmp=ptr->next;
  294.         ge_free_item(ptr);
  295.       }
  296.  
  297.     } /* if */
  298.  
  299.     /* add segment block to free list */
  300.     ge_open[pos].next = ge_dsfree;
  301.     ge_dsfree = pos; 
  302.  
  303.   } /* if */
  304.  
  305. } /* ge_delete_segment */
  306.  
  307. /*****************************************************************************
  308.  
  309.      ge_display_list will get the display list of a segment.
  310.  
  311.   Input
  312.     segno - number of segment
  313.  
  314.   Output
  315.     Return pointer to display list of segment, 0 if segment is not found.
  316.  
  317. *****************************************************************************/
  318.  
  319. struct list *ge_display_list(segno)
  320. int segno;
  321. {
  322.   int pos;
  323.  
  324.   if ((pos=ge_index(segno)) >= 0) {
  325.     return(&(ge_open[pos]));
  326.   }
  327.   else
  328.     return(0);
  329.  
  330. } /* ge_display_list */
  331. @//E*O*F display.c//
  332. chmod u=r,g=r,o=r display.c
  333.  
  334. echo x - ps.c
  335. sed 's/^@//' > "ps.c" <<'@//E*O*F ps.c//'
  336.  
  337. static char SccsId[] = "@(#)ps.c    1.2 6/8/87 Copyright 1987 SBCS-chan";
  338.  
  339. /*****************************************************************************
  340.  
  341.           (c) Copyright 1987 
  342.  
  343.           Lap-Tak Chan
  344.           Computer Science Department
  345.           State University of New York at Stony Brook
  346.           Stony Brook, NY 11794
  347.  
  348.     This software and its documentation may be used, copied, and
  349.   distributed, provided that this legend appear in all copies and
  350.   that it is not copied or distributed for a profit.
  351.  
  352.   No representations is made about the suitability of this software
  353.   for any purpose.  It is provided "as is" with no support and no
  354.   express or implied warranty.
  355.  
  356. *****************************************************************************/
  357.  
  358. /*****************************************************************************
  359.  
  360.                         PostScript Interface
  361.                         ====================
  362.  
  363.     This file contains the PostScript interface routines of graphedit
  364.   which can write the display lists in PostScript and rebuild the display
  365.   lists from the written PostScript.
  366.  
  367. *****************************************************************************/
  368.  
  369. #include "display.h"
  370. #include <usercore.h>
  371. #include <stdio.h>
  372. #include <string.h>
  373.  
  374. #define DEGPERRAD 180./PI
  375. #define PSHEADER "ps.head" /* name of the header file */
  376. static FILE *writefile;
  377. static char pshead[80];
  378. struct list *ge_display_list();
  379.  
  380. /*****************************************************************************
  381.  
  382.     ps_init do the necessary initialization before writing segments to the
  383.   output file.  It will copy the header file as the beginning of the output
  384.   file, and define how the graphedit coordinate system will be put on
  385.   8.5 x 11 paper according to save_attr.
  386.  
  387. *****************************************************************************/
  388.  
  389. ps_init()
  390. {
  391.   float sx, sy, tx, ty;
  392.   FILE *header;
  393.   char buf[512];
  394.   extern struct saveattr save_attr;
  395.   float width, height;
  396.  
  397.   /* copy header to output file */
  398.   if ( ! (header=fopen(pshead, "r"))) {
  399.     fprintf(writefile, "%% Header file %s should be included here\n",pshead);
  400.   }
  401.   else {
  402.  
  403.     /* copy the header file to the output file */
  404.     while ( fgets(buf, 512, header) ) {
  405.       fputs(buf, writefile);
  406.     }
  407.     /* close the header file */
  408.     fclose(header);
  409.   }
  410.  
  411.   if ( save_attr.rotate ) {
  412.  
  413.     /* rotate picture */
  414.     width = save_attr.height;
  415.     height = save_attr.width;
  416.  
  417.     /* determine the scale, height and width of picture */
  418.     sx=save_attr.height*7.2/GE_WIN_X;
  419.     sy=save_attr.width*7.2/GE_WIN_Y;
  420.     switch ( save_attr.fix ) {
  421.       case 1:
  422.         sx=sy;
  423.         width=GE_WIN_X/GE_WIN_Y*height;
  424.         break;
  425.       case 2:
  426.         sy=sx;
  427.         height=GE_WIN_Y/GE_WIN_X*width;
  428.         break;
  429.     } /* switch */
  430.  
  431.     /* determine the offset necessary */
  432.     if ( save_attr.center ) {
  433.       tx = (55./width-0.5)*GE_WIN_X;
  434.       ty = (-42.5/height-0.5)*GE_WIN_Y;
  435.     }
  436.     else {
  437.       tx = ((110.-save_attr.offb)/width-1.)*GE_WIN_X;
  438.       ty = ((-save_attr.offa)/height-1.)*GE_WIN_Y;
  439.     }
  440.  
  441.     fprintf(writefile, "90. rotate ");
  442.  
  443.   }
  444.  
  445.   else {
  446.     width = save_attr.width;
  447.     height = save_attr.height;
  448.  
  449.     /* determine the scale, height and width of the picture */
  450.     sx=save_attr.width*7.2/GE_WIN_X;
  451.     sy=save_attr.height*7.2/GE_WIN_Y;
  452.     switch (save_attr.fix) {
  453.       case 1:
  454.         sy=sx;
  455.         height=GE_WIN_Y/GE_WIN_X*width;
  456.         break;
  457.       case 2:
  458.         sx=sy;
  459.         width=GE_WIN_X/GE_WIN_Y*height;
  460.         break;
  461.     } /* switch */
  462.  
  463.     /* determine the offset necessary */
  464.     if ( save_attr.center ) {
  465.       tx = (42.5/width-0.5)*GE_WIN_X;
  466.       ty = (55./height-0.5)*GE_WIN_Y;
  467.     }
  468.     else {
  469.       tx = save_attr.offa/width*GE_WIN_X;
  470.       ty = ((110.-save_attr.offb)/height-1.)*GE_WIN_Y;
  471.     }
  472.  
  473.   }
  474.  
  475.   /* define the graphedit coordinate system */
  476.   fprintf(writefile, "%f %f scale %f %f translate\n", sx, sy,
  477.     tx,ty);
  478.  
  479.   /* header which will be used to find the real beginning of the
  480.      saved segments */
  481.   fprintf(writefile, "%% graphedit.save v%s\n", GE_VERSION);
  482.  
  483. } /* ps_init */
  484.  
  485. /*****************************************************************************
  486.  
  487.     ps_done just do whatever necessary after saving all these segments.
  488.  
  489. *****************************************************************************/
  490.  
  491. ps_done()
  492. {
  493.   FILE *tail;
  494.   char buf[512];
  495.  
  496.   fprintf(writefile, "GE_TERM\n");
  497.  
  498. } /* ps_done */
  499.  
  500. /*****************************************************************************
  501.  
  502.     ps_setfont will generate the change of font in PostScript.
  503.  
  504. *****************************************************************************/
  505.  
  506. ps_setfont(font)
  507. int font;
  508. {
  509.  
  510.   fprintf(writefile, "%d GE_SET_FONT\n", font);
  511.  
  512. } /* ps_setfont */
  513.  
  514. /*****************************************************************************
  515.  
  516.     ps_setlinestyle will generate the change of line style in PostScript.
  517.  
  518. *****************************************************************************/
  519.  
  520. ps_setlinestyle(type)
  521. int type;
  522. {
  523.  
  524.   fprintf(writefile, "%d GE_SET_LINESTYLE\n", type);
  525.  
  526. } /* ps_setlinestyle */
  527.  
  528. /*****************************************************************************
  529.  
  530.     ps_draw_seg will draw a segment in PostScript according to its display
  531.   list.
  532.  
  533.   Input
  534.     list - display list of segment
  535.  
  536. *****************************************************************************/
  537.  
  538. ps_draw_seg(list)
  539. struct list *list;
  540. {
  541.   struct list_item *ptr;
  542.   static struct list_item closeinstr={GE_CLOSE, 0., 0., NULL};
  543.  
  544.   /* abort if the display list of the segment is empty */
  545.   if ( !(ptr=list->d_list) )
  546.     return;
  547.  
  548.   /* set the transformation of the segment */
  549.   fprintf(writefile, "GE_NEW_SEG\n%f %f GE_TRANSLATE\n%f GE_ROTATE\n%f %f GE_SCALE\n",
  550.           list->attr.tx, list->attr.ty, list->attr.ang * DEGPERRAD,
  551.           list->attr.sx, list->attr.sy);
  552.  
  553.   /* set the attribtes of the segment */
  554.   fprintf(writefile, "%d GE_SET_COLOR\n", list->attr.color);
  555.   fprintf(writefile, "%d GE_SET_LINEWIDTH\n",
  556.           list->attr.linewidth);
  557.   fprintf(writefile, "%d GE_SET_CHARSIZE\n", list->attr.charsize);
  558.   ps_setlinestyle(list->attr.linestyle);
  559.   ps_setfont(list->attr.font);
  560.  
  561.   /* scan the display list and execute the instructions to draw the
  562.      primitives */
  563.   ptr=ptr->next;
  564.   do {
  565.     ps_exec(ptr);
  566.     ptr=ptr->next;
  567.   } while ( ptr != list->d_list->next );
  568.  
  569.   /* close the segment */
  570.   ps_exec(&closeinstr);
  571.   fprintf(writefile, "GE_END_SEG\n");
  572.  
  573. } /* ps_draw_seg */
  574.  
  575. /*****************************************************************************
  576.  
  577.     ps_exec will execute an instruction and draw it in PostScript.
  578.  
  579.   Input
  580.     ptr - pointer to instruction
  581.  
  582. *****************************************************************************/
  583.  
  584. ps_exec(ptr)
  585. struct list_item *ptr;
  586. {
  587.   static float xbuff[512], ybuff[512];
  588.   static int lastinstr=0;
  589.   static int n=0;
  590.   int i;
  591.  
  592.   /* execute last polyline/polygon instruction if instruction indicates
  593.      end of the last instruction */
  594.   if ( lastinstr && ptr->instr != GE_CONT ) {
  595.     switch ( lastinstr ) {
  596.  
  597.       case GE_POLYLINE :
  598.         fprintf(writefile, "%.4f %.4f GE_POLYLINE\n", xbuff[0], ybuff[0]);
  599.         for (i=1; i<n; i++) {
  600.           fprintf(writefile, "%.4f %.4f GE_CONT\n", xbuff[i], ybuff[i]);
  601.         }
  602.         fprintf(writefile, "GE_END\n");
  603.         break;
  604.  
  605.       case GE_POLYGON:
  606.         fprintf(writefile, "%.4f %.4f GE_POLYGON\n", xbuff[0], ybuff[0]);
  607.         for (i=1; i<n; i++) {
  608.           fprintf(writefile, "%.4f %.4f GE_CONT\n", xbuff[i], ybuff[i]);
  609.         }
  610.         fprintf(writefile, "GE_END\n");
  611.         break;
  612.  
  613.       default: ;
  614.     }
  615.     lastinstr = n = 0;
  616.   }
  617.  
  618.   /* execute new instruction */
  619.   switch (ptr->instr) {
  620.  
  621.     /* instructions with single coordinate */
  622.     case GE_MOVE:
  623.       fprintf(writefile, "%.4f %.4f GE_MOVE\n", ptr->x, ptr->y);
  624.       break;
  625.  
  626.     case GE_LINE:
  627.       fprintf(writefile, "%.4f %.4f GE_LINE\n",  ptr->x, ptr->y);
  628.       break;
  629.  
  630.     case GE_ELLIPSE:
  631.       fprintf(writefile, "%.4f %.4f GE_ELLIPSE\n",  ptr->x, ptr->y);
  632.       break;
  633.  
  634.     case GE_ARC:
  635.       fprintf(writefile, "%.4f %.4f GE_ARC\n",  ptr->x, ptr->y);
  636.       break;
  637.  
  638.     case GE_ARCEXT:
  639.       fprintf(writefile, "%.4f GE_ARCEXT\n",  ptr->x);
  640.       break;
  641.  
  642.     case GE_CIRCLE:
  643.       fprintf(writefile, "%.4f GE_CIRCLE\n", ptr->x);
  644.       break;
  645.  
  646.     /* instruction with two or more coordinates */
  647.     case GE_POLYLINE:
  648.     case GE_POLYGON:
  649.       /* store instruction */
  650.       lastinstr=ptr->instr;
  651.  
  652.     case GE_CONT:
  653.       /* save coordinate of polyline/polygon */
  654.       xbuff[n] = ptr->x;
  655.       ybuff[n++] = ptr->y;
  656.       break;
  657.  
  658.     case GE_TEXT:
  659.       fprintf(writefile, "(%s) GE_TEXT\n", (char *)((int)ptr->x));
  660.       break;
  661.  
  662.     case GE_SETCOLOR:
  663.       fprintf(writefile, "%d GE_SET_COLOR\n", (int)ptr->x);
  664.       break;
  665.  
  666.     case GE_SETTYPELINE:
  667.       fprintf(writefile, "%d GE_SET_LINESTYLE\n", (int)ptr->x);
  668.       break;
  669.  
  670.     case GE_SETLINEWIDTH:
  671.       fprintf(writefile, "%d GE_SET_LINEWIDTH\n", (int)ptr->x);
  672.       break;
  673.  
  674.     case GE_SETFONT:
  675.       fprintf(writefile, "%d GE_SET_FONT\n", (int)ptr->x);
  676.       break;
  677.  
  678.     case GE_SETCHARSIZE:
  679.       fprintf(writefile, "%d GE_SET_CHARSIZE\n", (int)ptr->x);
  680.       break;
  681.  
  682.     case GE_FILL:
  683.       fprintf(writefile, "%d GE_FILL\n", (int)ptr->x);
  684.       break;
  685.  
  686.     case GE_CLOSE:
  687.       /* do nothing */
  688.       break;
  689.  
  690.     default :
  691.       /* check that all instructions are properly handled */
  692.       fprintf(stderr,
  693.               "Internal Error-Action for instruction %d missing.\n",
  694.               ptr->instr);
  695.        break;
  696.  
  697.   } /* switch */
  698.  
  699. } /* ps_exec */
  700.  
  701. /*****************************************************************************
  702.  
  703.     ps_write will write the picture as a complete PostScrip program in
  704.   the already opened outfile.  It will copy a header file to outfile,
  705.   scan the segment list and write every segment (except the sample segments)
  706.   in PostScript.
  707.  
  708.     The directory where the header file is located will be defined by the
  709.   environment GELIB.  If GELIB is not defined, GE_DEFAULTLIB will be used.
  710.  
  711.   Input
  712.     outfile - opened output stream to write on
  713.  
  714. *****************************************************************************/
  715.  
  716. ps_write(outfile)
  717. FILE *outfile;
  718. {
  719.   extern int ge_seglist;
  720.   extern struct list ge_open[];
  721.   int i;
  722.   char *libdir;
  723.  
  724.   /* save it so that ps_exec will be able to access it */
  725.   writefile=outfile;
  726.  
  727.   /* generate the name for the header file */
  728.   if ( !(libdir = (char *)getenv("GELIB")) )
  729.     libdir=GE_DEFAULTLIB;
  730.   (void)strcpy(pshead,libdir);
  731.   (void)strcat(pshead,"/");
  732.   (void)strcat(pshead,PSHEADER);
  733.  
  734.   /* initialize */
  735.   ps_init();
  736.  
  737.   /* scan the segment list and write every user segment */
  738.   for ( i=ge_seglist; i; i=ge_open[i].next ) {
  739.     if ( ge_open[i].segno >= GE_MIN_SEG && (! ge_open[i].attr.deleted) ) {
  740.       ps_draw_seg(&(ge_open[i]));
  741.     } /* if */
  742.   } /* for */
  743.  
  744.   ps_done();
  745.  
  746. } /* ps_write */
  747.  
  748. /*****************************************************************************
  749.  
  750.     ps_write_seg will write one segment in PostScript to outfile.  The
  751.   output file is not a complete PostScrip program and thus cannot be printed.
  752.  
  753.   Input
  754.     outfile - opened output stream to write on
  755.     segno - segment to write
  756.  
  757. *****************************************************************************/
  758.  
  759. ps_write_seg(outfile, segno)
  760. FILE *outfile;
  761. int segno;
  762. {
  763.   struct list *list;
  764.  
  765.   writefile=outfile;
  766.  
  767.   /* get display list of segment */
  768.   list=ge_display_list(segno);
  769.  
  770.   /* write header */
  771.   fprintf(writefile, "%% graphedit.save v%s\n", GE_VERSION);
  772.  
  773.   /* write segment in PostScript */
  774.   ps_draw_seg(list);
  775.  
  776. } /* ps_write_seg */
  777.  
  778. /*****************************************************************************
  779.  
  780.     ps_load will rebuild the display list of the segments written in infile.
  781.   It will scan the file for the mark of the beginning of data.  Then it
  782.   will read and process each line until the mark for the end of data is
  783.   encountered.
  784.  
  785.   Input
  786.     infile - opened input stread to read from
  787.  
  788. *****************************************************************************/
  789.  
  790. ps_load(infile)
  791. FILE *infile;
  792. {
  793.   char inbuf[512];
  794.  
  795.   /* skip header until mark of  beginning of data */
  796.   for (; (fgets(inbuf,512,infile)) && 
  797.          (strncmp(inbuf, "% graphedit.save",16)););
  798.  
  799.   if ( inbuf[0] != '%' ) {
  800.     /* abort if header cannot be found */
  801.     return(1);
  802.   }
  803.  
  804.   /* read and process each line in infile until the instruction GE_TERM
  805.      marking the end of the file is encountered */
  806.   while ( (fgets(inbuf,512,infile) &&
  807.           (strcmp(inbuf,"GE_TERM")) )) {
  808.     /* process line */
  809.     ps_read(inbuf);
  810.   } /* while */
  811.  
  812.   return(0);
  813.  
  814. } /* ps_load */
  815.  
  816. /*****************************************************************************
  817.  
  818.     ps_cmd2instr will return the instruction for a command in the PostScript
  819.   input.
  820.  
  821.   Input
  822.     command - command in PostScript
  823.  
  824.   Output
  825.     Return internal instruction corresponding to the command.
  826.  
  827. *****************************************************************************/
  828.  
  829. ps_cmd2instr(command)
  830. char *command;
  831. {
  832.   struct cmdinstr {
  833.     char *cmd;
  834.     int instr;
  835.   } ;
  836.  
  837.   /* a map of command to instruction */
  838.   static struct cmdinstr cmdinstr[] = {
  839.     { "GE_SET_FONT", GE_SETFONT },
  840.     { "GE_SET_LINESTYLE", GE_SETTYPELINE },
  841.     { "GE_SET_COLOR", GE_SETCOLOR },
  842.     { "GE_SET_LINEWIDTH", GE_SETLINEWIDTH},
  843.     { "GE_NEW_SEG", GE_NEW },
  844.     { "GE_END_SEG", GE_CLOSE },
  845.     { "GE_TRANSLATE", GE_TRANSLATE },
  846.     { "GE_ROTATE", GE_ROTATE },
  847.     { "GE_SCALE", GE_SCALE },
  848.     { "GE_MOVE", GE_MOVE },
  849.     { "GE_LINE", GE_LINE },
  850.     { "GE_POLYLINE", GE_POLYLINE },
  851.     { "GE_POLYGON", GE_POLYGON },
  852.     { "GE_TEXT", GE_TEXT },
  853.     { "GE_CIRCLE", GE_CIRCLE },
  854.     { "GE_ELLIPSE", GE_ELLIPSE },
  855.     { "GE_CONT", GE_CONT },
  856.     { "GE_SET_CHARSIZE", GE_SETCHARSIZE },
  857.     { "GE_FILL", GE_FILL },
  858.     { "GE_ARC", GE_ARC },
  859.     { "GE_ARCEXT", GE_ARCEXT},
  860.     { "", 0 }
  861.   };
  862.  
  863.   int i;
  864.  
  865.   /* scan for the location of the command in the map */
  866.   for ( i=0; cmdinstr[i].instr && strcmp(cmdinstr[i].cmd, command); i++ );
  867.  
  868.   /* return instruction for command */
  869.   return(cmdinstr[i].instr);
  870.  
  871. } /* ps_cmd2instr */
  872.  
  873. /*****************************************************************************
  874.  
  875.     ps_read will process a command in a line of input.  Each command may
  876.   be composed of 1 to 3 fields.  The last field corresponds to an attribute
  877.   or instruction while the others are parameters to the commands.
  878.  
  879.   Input
  880.     inbuf - input buffer containing a line of input from the input file
  881.  
  882. *****************************************************************************/
  883.  
  884. ps_read(inbuf)
  885. char *inbuf;
  886. {
  887.   static int ps_segno;
  888.   static struct list *seginfo;
  889.   char buf1[80], buf2[80], buf3[80], *command;
  890.   int fields, instr, inexec;
  891.   float x,y;
  892.  
  893.   /* handle GE_TEXT */
  894.   if ( inbuf[0] == '(' ) {
  895.  
  896.     char *ptr;
  897.  
  898.     /* get the end of the text string */
  899.     if ( ptr=(char *)rindex(inbuf,')') ) {
  900.  
  901.       *ptr='\0';
  902.       strcpy((ptr=(char *)malloc(strlen(inbuf))),&(inbuf[1]));
  903.       ge_graph(ps_segno, GE_TEXT, (float)((int)ptr),0.);
  904.  
  905.     }
  906.     return;
  907.   }
  908.  
  909.   /* separate the command into up to three fields */
  910.   if ( !(fields=sscanf(inbuf, "%s%s%s", buf1, buf2, buf3)) ) {
  911.     return;
  912.   }
  913.  
  914.   /* command is the last field */
  915.   switch ( fields ) {
  916.     case 1: command=buf1;
  917.             break;
  918.     case 2: command=buf2;
  919.             break;
  920.     case 3: command=buf3;
  921.             break;
  922.     default: break;
  923.   } /* switch */
  924.  
  925.   /* get instruction corresponding to command */
  926.   if ( instr=ps_cmd2instr(command) ) {
  927.  
  928.     switch ( instr ) {
  929.       /* instructions with two parameters */
  930.       case GE_MOVE:
  931.       case GE_LINE:
  932.       case GE_POLYLINE:
  933.       case GE_POLYGON:
  934.       case GE_CONT:
  935.       case GE_ELLIPSE:
  936.       case GE_ARC:
  937.         sscanf(buf1,"%f",&x); sscanf(buf2,"%f",&y);
  938.         ge_graph(ps_segno, instr, x, y);
  939.         inexec=1;
  940.         break;
  941.  
  942.       /* instructions with one parameter */
  943.       case GE_CIRCLE:
  944.       case GE_ARCEXT:
  945.       case GE_FILL:
  946.         sscanf(buf1, "%f",&x);
  947.         ge_graph(ps_segno, instr, x, 0.);
  948.         inexec=1;
  949.         break;
  950.  
  951.       /* initial attributes or change of attributes */
  952.       case GE_SETCOLOR:
  953.       case GE_SETTYPELINE:
  954.       case GE_SETLINEWIDTH:
  955.       case GE_SETFONT:
  956.       case GE_SETCHARSIZE:
  957.         sscanf(buf1,"%f",&x);
  958.  
  959.         if ( ! inexec )
  960.           /* set initial attribues */
  961.           switch (instr) {
  962.             case GE_SETCOLOR:
  963.               seginfo->attr.color = (int)x;
  964.               break;
  965.             case GE_SETTYPELINE:
  966.               seginfo->attr.linestyle = (int)x;
  967.               break;
  968.             case GE_SETLINEWIDTH:
  969.               seginfo->attr.linewidth = (int)x;
  970.               break;
  971.             case GE_SETFONT:
  972.               seginfo->attr.font = (int) x;
  973.               break;
  974.             case GE_SETCHARSIZE:
  975.               seginfo->attr.charsize = (int) x;
  976.           }
  977.  
  978.         else {
  979.           /* change attribute */
  980.           ge_graph(ps_segno, instr, x, 0.);
  981.         }
  982.         break;
  983.  
  984.       /* trnasformations */
  985.       case GE_TRANSLATE:
  986.         sscanf(buf1,"%f",&(seginfo->attr.tx));
  987.         sscanf(buf2,"%f",&(seginfo->attr.ty));
  988.         break;
  989.       case GE_ROTATE:
  990.         sscanf(buf1,"%f",&(seginfo->attr.ang));
  991.         seginfo->attr.ang /= DEGPERRAD;
  992.         break;
  993.       case GE_SCALE:
  994.         sscanf(buf1,"%f",&(seginfo->attr.sx));
  995.         sscanf(buf2,"%f",&(seginfo->attr.sy));
  996.         break;
  997.  
  998.       /* start new segment */
  999.       case GE_NEW:
  1000.         /* create new segment */
  1001.         ps_segno=make_new_seg(0);
  1002.         seginfo=(struct list *)ge_display_list(ps_segno);
  1003.         inexec=0;
  1004.         break;
  1005.  
  1006.       /* close segment */
  1007.       case GE_CLOSE:
  1008.         seginfo=0;
  1009.         /* draw segment */
  1010.         ge_draw(ps_segno);
  1011.         break;
  1012.  
  1013.       default:
  1014.         /* check that all instructions are properly handled */
  1015.         fprintf(stderr, "Internal Error-Action for instruction %d missing.\n",
  1016.           instr);
  1017.         break;
  1018.  
  1019.     } /* switch */
  1020.  
  1021.   } /* if */
  1022.  
  1023. } /* ps_read */
  1024.  
  1025. @//E*O*F ps.c//
  1026. chmod u=r,g=r,o=r ps.c
  1027.  
  1028. echo x - pic.c
  1029. sed 's/^@//' > "pic.c" <<'@//E*O*F pic.c//'
  1030.  
  1031. static char SccsId[] = "@(#)pic.c    1.1 6/8/87 Copyright 1987 SBCS-chan";
  1032.  
  1033. /*****************************************************************************
  1034.  
  1035.           (c) Copyright 1987 
  1036.  
  1037.           Lap-Tak Chan
  1038.           Computer Science Department
  1039.           State University of New York at Stony Brook
  1040.           Stony Brook, NY 11794
  1041.  
  1042.     This software and its documentation may be used, copied, and
  1043.   distributed, provided that this legend appear in all copies and
  1044.   that it is not copied or distributed for a profit.
  1045.  
  1046.   No representations is made about the suitability of this software
  1047.   for any purpose.  It is provided "as is" with no support and no
  1048.   express or implied warranty.
  1049.  
  1050. *****************************************************************************/
  1051.  
  1052. /*****************************************************************************
  1053.  
  1054.                           Pic Output
  1055.                           ==========
  1056.  
  1057.     This file contains routines which write the diagram in format suitable
  1058.   as input to pic(1), which is a picture drawing preprocessor to troff.
  1059.  
  1060. *****************************************************************************/
  1061.  
  1062. #include "display.h"
  1063. #include <stdio.h>
  1064. #include <string.h>
  1065. #include <math.h>
  1066.  
  1067. #define DEGPERRAD 180./PI
  1068. static FILE *writefile; /* file to write diagram to */
  1069. struct list *ge_display_list();
  1070. static struct attr pic_attr; /* current attributes used for current segment */
  1071. static float sina, cosa;
  1072. static float pic_rms; /* root mean square of x and y scale of current segment */
  1073.  
  1074. /* mapping of graphedit fonts to troff fonts */
  1075. static char *pic_font[]=
  1076.   { "R", "R", "S", "I", "B" };
  1077.  
  1078. /*****************************************************************************
  1079.  
  1080.     pic_init will do the necessary initialization for the writing.
  1081.  
  1082. *****************************************************************************/
  1083.  
  1084. pic_init()
  1085. {
  1086.   float sx, sy;
  1087.   FILE *header;
  1088.   char buf[512];
  1089.   extern struct saveattr save_attr;
  1090.  
  1091.   /* indicate beginning of pic input */
  1092.   fprintf(writefile, ".PS %.2f\n", save_attr.width/10.);
  1093.  
  1094.   /* to make pic using full graphedit coordinates */
  1095.   fprintf(writefile, "move to (%.4f,%.4f)\n", GE_WIN_X, GE_WIN_Y);
  1096.  
  1097. } /* pic_init */
  1098.  
  1099. /*****************************************************************************
  1100.  
  1101.     pic_done do anything necessary to clean up after the writing.
  1102.  
  1103. *****************************************************************************/
  1104.  
  1105. pic_done()
  1106. {
  1107.   FILE *tail;
  1108.   char buf[512];
  1109.  
  1110.   /* indicate end of pic input */
  1111.   fprintf(writefile, ".PE\n");
  1112.  
  1113. } /* pic_done */
  1114.  
  1115. /*****************************************************************************
  1116.  
  1117.     pic_xform transforms a coordinate of the current segment to the world
  1118.   coordiante.
  1119.  
  1120.   Input
  1121.     ix, iy - coordinate in space of current segment
  1122.  
  1123.   Output
  1124.     ox, oy - corresponding world coordinate of (ix,iy) according to
  1125.              transformatio of current segment.
  1126.  
  1127. *****************************************************************************/
  1128.  
  1129. pic_xform(ix, iy, ox, oy)
  1130. float ix, iy, *ox, *oy;
  1131. {
  1132.   *ox = cosa * ix * pic_attr.sx - sina * iy * pic_attr.sy + pic_attr.tx;
  1133.   *oy = sina * ix * pic_attr.sx + cosa * iy * pic_attr.sy + pic_attr.ty;
  1134.  
  1135. } /* pic_xform */
  1136.  
  1137. /*****************************************************************************
  1138.  
  1139.      pic_charsize set a new character size in pic.  The actual character
  1140.   size is determined from the character size of the current segment, the
  1141.   width of the picture, and the scale of the current segment.
  1142.  
  1143. *****************************************************************************/
  1144.  
  1145. pic_charsize()
  1146. {
  1147.   float charsize;
  1148.  
  1149.   charsize = pic_attr.charsize * pic_rms * save_attr.width / 42.;
  1150.   return((int)charsize);
  1151.  
  1152. } /* pic_charsize */
  1153.  
  1154. /*****************************************************************************
  1155.  
  1156.     pic_linestyle set a new line style according to the line style of the
  1157.   current segment.
  1158.  
  1159. *****************************************************************************/
  1160.  
  1161. pic_linestyle()
  1162. {
  1163.   /* mapping of graphedit line style to pic line style */
  1164.   static char *pic_style[] =
  1165.     { 0, "dotted 3", "dashed 6", "dashed 2" };
  1166.  
  1167.   if ( pic_style[pic_attr.linestyle] )
  1168.     fprintf(writefile, " %s", pic_style[pic_attr.linestyle]);
  1169.  
  1170. } /* pic_linestyle */
  1171.  
  1172. /*****************************************************************************
  1173.  
  1174.     pic_linewidth determine the line width in pic according to the line
  1175.   width of the current segment.
  1176.  
  1177.   Output
  1178.     Return the line width determined.
  1179.  
  1180. *****************************************************************************/
  1181.  
  1182. pic_linewidth()
  1183. {
  1184.   /* this formula may need adjustment */
  1185.   return ((pic_attr.linewidth)*12+2);
  1186.  
  1187. } /* pic_linewidth */
  1188.  
  1189. /* set the line width in pic */
  1190. #define pic_set_linewidth() fprintf(writefile,".ps %d\n",\
  1191.    pic_linewidth())
  1192.  
  1193. /*****************************************************************************
  1194.  
  1195.     pic_sim_ellipse will simulate the drawing of an ellipse by dividing
  1196.   the ellipse into a number of segments and draw each segment with an
  1197.   arc.  This is necessary because pic cannot draw rotated ellipse.
  1198.  
  1199.     Coordinates of points on the ellipse are determined by transformation
  1200.   of points on a circle at (0,0) with radius 1.
  1201.  
  1202.   Input
  1203.     currx, curry - current world cordinate
  1204.     a,b - half of width and height of ellipse
  1205.  
  1206. *****************************************************************************/
  1207.  
  1208. pic_sim_ellipse(currx, curry, a, b)
  1209. float currx, curry, a, b;
  1210. {
  1211.  
  1212. #define PLT_CIRINT 20 /* number of segments to divide into */
  1213. #define PLT_CIRSIZE PLT_CIRINT*2+1 /* size of array necessary */
  1214.  
  1215.   static int pic_mdl_make = 0;
  1216.   static float pic_cir_x[PLT_CIRSIZE];
  1217.   static float pic_cir_y[PLT_CIRSIZE];
  1218.   extern float ge_radius(); /* from misc.c */
  1219.   float radius; /* radius of arc */
  1220.   float x1, y1, x2, y2, x3, y3; /* start, mid and end points of arc */
  1221.   int i;
  1222.  
  1223.   /* put the coordinates of points on a circle with center at (0,0)
  1224.      and radius 1 in pic_cir_x and pic_cir_y at the first time */
  1225.   if ( ! pic_mdl_make ) {
  1226.     int count;
  1227.     float intv;
  1228.  
  1229.     intv = PI / PLT_CIRINT;
  1230.     for (count=0; count < PLT_CIRSIZE; count ++ ) {
  1231.       pic_cir_x[count]=cos(intv*count);
  1232.       pic_cir_y[count]=sin(intv*count);
  1233.     } /* for */
  1234.     pic_mdl_make = 1;
  1235.   } /* if */
  1236.  
  1237.   /* determine the world coordinate of the first point and move there */
  1238.   pic_xform(pic_cir_x[0]*a, pic_cir_y[0]*b, &x3, &y3);
  1239.   fprintf(writefile, "move to  (%.4f,%.4f)\n",
  1240.           x3+currx-pic_attr.tx, y3+curry-pic_attr.ty);
  1241.  
  1242.   /* draw the arcs */
  1243.   for ( i=0; i<PLT_CIRSIZE-1; i+=2 ) {
  1244.  
  1245.     /* make the end point of the last arc the start point */
  1246.     x1=x3; y1=y3;
  1247.  
  1248.     /* determine the world coordinate of the mid point and the end point */
  1249.     pic_xform(pic_cir_x[i+1]*a,pic_cir_y[i+1]*b, &x2, &y2);
  1250.     pic_xform(pic_cir_x[i+2]*a,pic_cir_y[i+2]*b, &x3, &y3);
  1251.  
  1252.     /* determine the radius of the arc passing the start, mid and end points */
  1253.     radius = ge_radius(x1,y1,x2,y2,x3,y3);
  1254.  
  1255.      /* draw the arc */
  1256.     fprintf(writefile, "arc to (%.4f,%.4f) radius %.4f\n",
  1257.             x3+currx-pic_attr.tx, y3+curry-pic_attr.ty, radius);
  1258.  
  1259.   } /* draw ellipse */
  1260.  
  1261. } /* pic_sim_ellipse */
  1262.  
  1263. /*****************************************************************************
  1264.  
  1265.     pic_sim_arc will simulate an arc which is not a real arc after
  1266.   transformation of the current segment with a number of small arcs.
  1267.  
  1268.   Input
  1269.     currx, curry - center of arc in world coordinate
  1270.     ang1 - start angle in radian, 0 <= ang1 <= 2*PI
  1271.     ang2 - end angle in radian, 0 <= ang2 < = 2*PI
  1272.     arcradius - radius of arc
  1273.  
  1274. *****************************************************************************/
  1275.  
  1276. pic_sim_arc(currx, curry, ang1, ang2, arcradius)
  1277. float currx, curry, ang1, ang2, arcradius;
  1278. {
  1279.   /* draw arc from smalll arcs */
  1280.   float intv, radius;
  1281.   extern float ge_radius();
  1282.   int count;
  1283.   float x1,y1,x2,y2,x3,y3,ang;
  1284.  
  1285.   /* ensure ang1 < ang2 */
  1286.   if ( ang1 > ang2 )
  1287.     ang1 -= 2*PI;
  1288.  
  1289.   /* determine number of segmnets to divide into with a minimum of 3 */
  1290.   intv = PI / PLT_CIRINT;
  1291.   count = (int)((ang2-ang1)/(2*intv));
  1292.   if ( count < 3 ) count = 3;
  1293.  
  1294.   intv = (ang2-ang1)/(count*2);
  1295.  
  1296.   /* determine the world coordinate of the first point and move there */
  1297.   pic_xform(cos(ang1)*radius,sin(ang1)*arcradius,&x3,&y3);
  1298.   fprintf(writefile, "move to (%.4f,%.4f)\n",
  1299.     x3+currx-pic_attr.tx,y3+curry-pic_attr.ty);
  1300.  
  1301.   /* draw the arcs */
  1302.   for ( ang = ang1; ang< (ang2-2*intv); ang += 2*intv) {
  1303.  
  1304.     /* make the end point of the last arc the start point */
  1305.     x1=x3; y1=y3;
  1306.  
  1307.     /* determine the world coordinate of the mid point and the end point */
  1308.     pic_xform(cos(ang+intv)*arcradius,
  1309.               sin(ang+intv)*arcradius, &x2, &y2);
  1310.     pic_xform(cos(ang+2*intv)*arcradius,
  1311.               sin(ang+2*intv)*arcradius, &x3, &y3);
  1312.  
  1313.     /* determine the radius of the arc passing the start, mid and end point */
  1314.     radius=ge_radius(x1,y1,x2,y2,x3,y3);
  1315.  
  1316.     /* draw the arc */
  1317.     fprintf(writefile, "arc to (%.4f,%.4f) radius %.4f\n",
  1318.       x3+currx-pic_attr.tx, y3+curry-pic_attr.ty, radius);
  1319.  
  1320.   } /* for */
  1321.  
  1322. }  /* draw arcs */
  1323.  
  1324. /*****************************************************************************
  1325.  
  1326.     plt_exec will execute an instruction.
  1327.  
  1328.   Input
  1329.     ptr - pointer to instruction
  1330.  
  1331. *****************************************************************************/
  1332.  
  1333. pic_exec(ptr)
  1334. struct list_item *ptr;
  1335. {
  1336.   static float xbuff[512], ybuff[512];
  1337.   static int lastinstr=0;
  1338.   static int n=0; /* number of points in polygon/polyline */
  1339.   static float currx, curry; /* current point */
  1340.   int i;
  1341.  
  1342.   /* execute last polyline/polygon instruction if instruction indicates
  1343.      end of the last instruction */
  1344.   if ( lastinstr && ptr->instr != GE_CONT ) {
  1345.     switch ( lastinstr ) {
  1346.       case GE_POLYLINE :
  1347.         /* draw polyline */
  1348.         for (i=0; i<n; i++) {
  1349.           fprintf(writefile, "line to (%.4f,%.4f)", xbuff[i], ybuff[i]);
  1350.           pic_linestyle(); /* specify line style */
  1351.           fprintf(writefile, "\n");
  1352.         } /* for */
  1353.  
  1354.         /* move to new current point */
  1355.         currx = xbuff[n-1];
  1356.         curry = ybuff[n-1];
  1357.         break;
  1358.  
  1359.       case GE_POLYGON:
  1360.         /* draw polygon */
  1361.         fprintf(writefile, "move to (%.4f,%.4f)\n", xbuff[0], ybuff[0]);
  1362.         for (i=1; i<n; i++) {
  1363.           fprintf(writefile, "line to (%.4f,%.4f)", xbuff[i], ybuff[i]);
  1364.           pic_linestyle(); /* specify line style */
  1365.           fprintf(writefile, "\n");
  1366.         } /* for */
  1367.         /* draw last line */
  1368.         fprintf(writefile, "line to (%.4f,%.4f)", xbuff[0], ybuff[0]);
  1369.         pic_linestyle();
  1370.         fprintf(writefile, "\n");
  1371.  
  1372.         /* update current position */
  1373.         currx = xbuff[0];
  1374.         curry = ybuff[0];
  1375.         break;
  1376.       default: ;
  1377.     }
  1378.     lastinstr = n = 0;
  1379.   }
  1380.  
  1381.   /* execute new instruction */
  1382.   switch (ptr->instr) {
  1383.  
  1384.     /* instructions with single coordinate */
  1385.     case GE_MOVE:
  1386.       /* move */
  1387.       pic_xform(ptr->x, ptr->y, &currx, &curry);
  1388.       fprintf(writefile, "move to (%.4f,%.4f)\n", currx, curry);
  1389.       break;
  1390.  
  1391.     case GE_LINE:
  1392.       /* line */
  1393.       pic_xform(ptr->x, ptr->y, &currx, &curry);
  1394.       fprintf(writefile, "line to (%.4f,%.4f)", currx, curry);
  1395.       pic_linestyle(); /* specify line style */
  1396.       fprintf(writefile, "\n");
  1397.       break;
  1398.  
  1399.     case GE_CIRCLE:
  1400.       {
  1401.         float radius;
  1402.  
  1403.         if ( pic_attr.sx == pic_attr.sy ) {
  1404.           /* draw a circle if it is a circle after transformation */
  1405.           fprintf(writefile, "circle radius %.4f at (%.4f,%.4f)\n",
  1406.             ptr->x*pic_attr.sx, currx, curry);
  1407.         }
  1408.         else {
  1409.           if ( pic_attr.ang == 0. ) {
  1410.             /* draw ellipse if rotation is 0 */
  1411.             fprintf(writefile, "ellipse at (%.4f, %.4f) ht %.4f wid %.4f\n",
  1412.               currx, curry, ptr->x*pic_attr.sy*2, ptr->x*pic_attr.sx*2);
  1413.           }
  1414.           else {
  1415.             /* simulate the ellipse */
  1416.             pic_sim_ellipse(currx,curry,ptr->x,ptr->x);
  1417.           }
  1418.         }
  1419.       }
  1420.       break;
  1421.  
  1422.     case GE_ELLIPSE:
  1423.       {
  1424.         float radius;
  1425.  
  1426.         if ( pic_attr.ang == 0. ) {
  1427.           /* draw ellipse if there is no rotation */
  1428.           fprintf(writefile, "ellipse at (%.4f, %.4f) ht %.4f wid %.4f\n",
  1429.             currx, curry, ptr->y*pic_attr.sy*2, ptr->x*pic_attr.sx*2);
  1430.         }
  1431.         else {
  1432.           /* simulate the ellipse */
  1433.           pic_sim_ellipse(currx,curry,ptr->x,ptr->y);
  1434.         }
  1435.       }
  1436.       break;
  1437.  
  1438.     case GE_ARC:
  1439.     case GE_ARCEXT:
  1440.       {
  1441.         static float ang1, ang2;
  1442.  
  1443.         if ( ptr->instr == GE_ARC ) {
  1444.           ang1 = ptr->x;
  1445.           ang2 = ptr->y;
  1446.         }
  1447.         else {
  1448.           if ( pic_attr.sx == pic_attr.sy ) {
  1449.             /* draw arc */
  1450.             float x1,y1,x2,y2;
  1451.  
  1452.             pic_xform(cos(ang1)*ptr->x,sin(ang1)*ptr->x,&x1,&y1);
  1453.             pic_xform(cos(ang2)*ptr->x,sin(ang2)*ptr->x,&x2,&y2);
  1454.             fprintf(writefile, "arc from (%.4f,%.4f) to (%.4f,%.4f) radius %.4f\n",
  1455.                     x1+currx-pic_attr.tx,y1+curry-pic_attr.ty,
  1456.                     x2+currx-pic_attr.tx,y2+curry-pic_attr.ty,
  1457.                     ptr->x*pic_attr.sx);
  1458.           }
  1459.           else {
  1460.             /* simulate the arc */
  1461.             pic_sim_arc(currx,curry,ang1,ang2,ptr->x);
  1462.           }
  1463.         }
  1464.       } /* GE_ARC, GE_ARCEXT */
  1465.       break;
  1466.             
  1467.     /* instruction with two or more coordinates */
  1468.     case GE_POLYLINE:
  1469.     case GE_POLYGON:
  1470.       lastinstr=ptr->instr; /* store instruction */
  1471.  
  1472.     case GE_CONT:
  1473.       /* save coordinate of polyline/polygon */
  1474.       pic_xform(ptr->x, ptr->y, &xbuff[n], &ybuff[n]);
  1475.       n++;
  1476.       break;
  1477.  
  1478.     case GE_TEXT:
  1479.       /* draw text */
  1480.       fprintf(writefile, ".ft %s\n.ps %d\n\"%s\" ljust at (%.4f,%.4f)\n.ps %d\n",
  1481.         pic_font[pic_attr.font],
  1482.         pic_charsize(),
  1483.         (char *)((int)ptr->x),
  1484.         currx, curry,
  1485.         pic_linewidth());
  1486.       break;
  1487.  
  1488.     case GE_SETTYPELINE:
  1489.       /* update line style */
  1490.       pic_attr.linestyle = (int)ptr->x;
  1491.       break;
  1492.  
  1493.     case GE_SETLINEWIDTH:
  1494.       /* update line width */
  1495.       pic_attr.linewidth = (int)ptr->x;
  1496.       pic_set_linewidth();
  1497.       break;
  1498.  
  1499.     case GE_SETFONT:
  1500.       /* update font */
  1501.       pic_attr.font = (int)ptr->x;
  1502.       break;
  1503.  
  1504.     case GE_SETCHARSIZE:
  1505.       /* update character size */
  1506.       pic_attr.charsize = (int)ptr->x;
  1507.       break;
  1508.  
  1509.     /* ignore these instructions */
  1510.     case GE_SETCOLOR:
  1511.     case GE_FILL:
  1512.     case GE_CLOSE:
  1513.       break;
  1514.  
  1515.     /* check whether all insturctions are properly handled */
  1516.     default :
  1517.       fprintf(stderr,
  1518.               "Internal Error-Action for instruction %d missing.\n",
  1519.               ptr->instr);
  1520.        break;
  1521.  
  1522.   } /* switch */
  1523.  
  1524. } /* pic_exec */
  1525.  
  1526. /*****************************************************************************
  1527.  
  1528.     pic_draw_seg will draw a segment according to its display list.  It
  1529.   just setup the attributes, and scan and execute the instructions on the
  1530.   instruction list.
  1531.  
  1532.   Input
  1533.     list - display list of segment
  1534.  
  1535. *****************************************************************************/
  1536.  
  1537. pic_draw_seg(list)
  1538. struct list *list;
  1539. {
  1540.   struct list_item *ptr;
  1541.   /* instruction to indicate end of segment */
  1542.   static struct list_item closeinstr={GE_CLOSE, 0., 0., NULL};
  1543.  
  1544.   /* ignore segment if the instruction list is empty */
  1545.   if ( !(ptr=list->d_list) )
  1546.     return;
  1547.  
  1548.   /* setup the initial attributes */
  1549.   pic_attr=list->attr;
  1550.   pic_rms = sqrt((double)((pic_attr.sx*pic_attr.sx+
  1551.                            pic_attr.sy*pic_attr.sy)/2));
  1552.   sina = (double)sin((double)pic_attr.ang);
  1553.   cosa = (double)cos((double)pic_attr.ang);
  1554.  
  1555.   /* initialize the line width */
  1556.   pic_set_linewidth();
  1557.  
  1558.   /* point at beginning of instruction list */
  1559.   ptr=ptr->next;
  1560.  
  1561.   /* scan instruction list */
  1562.   do {
  1563.     /* execution instruction */
  1564.     pic_exec(ptr);
  1565.     ptr=ptr->next;
  1566.  
  1567.   } while ( ptr != list->d_list->next );
  1568.  
  1569.   /* end of segment */
  1570.   pic_exec(&closeinstr);
  1571.  
  1572. } /* pic_draw_seg */
  1573.  
  1574. /*****************************************************************************
  1575.  
  1576.     pic_write will write the diagram in pic.  It scans the segment list and
  1577.   write every user segment not deleted.
  1578.  
  1579.   Input
  1580.     outfile - opened output stream
  1581.  
  1582. *****************************************************************************/
  1583.  
  1584. pic_write(outfile)
  1585. FILE *outfile;
  1586. {
  1587.   extern int ge_seglist;
  1588.   extern struct list ge_open[];
  1589.   int i;
  1590.  
  1591.   writefile=outfile;
  1592.  
  1593.   /* initialize pic */
  1594.   pic_init();
  1595.  
  1596.   /* scan the segment list */
  1597.   for ( i=ge_seglist; i; i=ge_open[i].next ) {
  1598.  
  1599.     /* write undeleted user segment */
  1600.     if ( ge_open[i].segno >= GE_MIN_SEG && (! ge_open[i].attr.deleted) ) {
  1601.       pic_draw_seg(&(ge_open[i]));
  1602.     } /* if */
  1603.   } /* for */
  1604.  
  1605.   /* terminate pic */
  1606.   pic_done();
  1607.  
  1608. } /* pic_write */
  1609. @//E*O*F pic.c//
  1610. chmod u=r,g=r,o=r pic.c
  1611.  
  1612. echo x - plot.c
  1613. sed 's/^@//' > "plot.c" <<'@//E*O*F plot.c//'
  1614.  
  1615. static char SccsId[] = "@(#)plot.c    1.1 6/8/87 Copyright 1987 SBCS-achan";
  1616.  
  1617. /*****************************************************************************
  1618.  
  1619.           (c) Copyright 1987 
  1620.  
  1621.           Lap-Tak Chan
  1622.           Computer Science Department
  1623.           State University of New York at Stony Brook
  1624.           Stony Brook, NY 11794
  1625.  
  1626.     This software and its documentation may be used, copied, and
  1627.   distributed, provided that this legend appear in all copies and
  1628.   that it is not copied or distributed for a profit.
  1629.  
  1630.   No representations is made about the suitability of this software
  1631.   for any purpose.  It is provided "as is" with no support and no
  1632.   express or implied warranty.
  1633.  
  1634. *****************************************************************************/
  1635.  
  1636. /*****************************************************************************
  1637.  
  1638.                         Plot Output
  1639.                         ===========
  1640.  
  1641.     This file contains routines which write the diagram in plot(5) format.
  1642.   The output file is actually written by routines in the plot(3) library.
  1643.  
  1644.   Filters for many graphic display terminal, laser printers, plotters
  1645.   and even regular terminals are available for files in plot(5) format.
  1646.  
  1647. *****************************************************************************/
  1648.  
  1649. #include "display.h"
  1650. #include <stdio.h>
  1651. #include <math.h>
  1652.  
  1653. /* scale used to maintain significance of coordinates when floating
  1654.    point coordinates are convert to integer coordinates */
  1655. #define SCALE 10
  1656.  
  1657. static double sina, cosa; /* sin and cos of rotation of current segment */
  1658.  
  1659. /* mapping of graphedit line styles to plot line styles */
  1660. static char *plt_linestyle[] =
  1661.   {  "solid", "dotted", "shortdashed", "dotdashed" };
  1662.  
  1663. static struct attr curr_attr; /* attributes of current segment */
  1664.  
  1665. /* from display.c */
  1666. extern int ge_seglist; /* segment list */
  1667. extern struct list ge_open[]; /* display list of segments */
  1668.  
  1669. /*****************************************************************************
  1670.  
  1671.     plt_write will write the diagram with routines in plot(3).  It
  1672.   scans the segment list and write every user segment not deleted.
  1673.  
  1674. *****************************************************************************/
  1675.  
  1676. plt_write()
  1677. {
  1678.   int i;
  1679.  
  1680.   /* initialize plot and define the coordiante space */
  1681.   openpl();
  1682.   space(0,0,(int)GE_WIN_X*SCALE, (int)GE_WIN_Y*SCALE);
  1683.  
  1684.   /* scan the segment list */
  1685.   for ( i=ge_seglist; i; i=ge_open[i].next ) {
  1686.  
  1687.     /* write undeleted user segment */
  1688.     if ( ge_open[i].segno >= GE_MIN_SEG && (! ge_open[i].attr.deleted) ) {
  1689.       plt_draw_seg(&(ge_open[i]));
  1690.     } /* if */
  1691.  
  1692.   } /* for */
  1693.  
  1694.   /* close plot */
  1695.   closepl();
  1696.  
  1697. } /* plt_write */
  1698.  
  1699. /*****************************************************************************
  1700.  
  1701.     plt_draw_seg will draw a segment according to its display list.  It
  1702.   just setup the attributes, and scan and execute the instructions on the
  1703.   instruction list.
  1704.  
  1705.   Input
  1706.     list - display list of segment
  1707.  
  1708. *****************************************************************************/
  1709.  
  1710. plt_draw_seg(list)
  1711. struct list *list;       
  1712. {
  1713.   struct list_item *ptr;
  1714.   /* instruction to indicate end of segment */
  1715.   static struct list_item closeinstr={GE_CLOSE, 0., 0., NULL};
  1716.  
  1717.   /* ignore segment if the instruction list is empty */
  1718.   if ( !(ptr=list->d_list) )
  1719.     return;
  1720.  
  1721.   /* setup the initial attributes */
  1722.   curr_attr = list->attr;
  1723.  
  1724.   /* initialize the line style */
  1725.   linemod(plt_linestyle[curr_attr.linestyle]);
  1726.  
  1727.   sina = (double)sin((double)curr_attr.ang);
  1728.   cosa = (double)cos((double)curr_attr.ang);
  1729.  
  1730.   /* point to beginning of instruction list */
  1731.   ptr=ptr->next;
  1732.  
  1733.   /* scan instruction list */
  1734.   do {
  1735.      /* execution instruction */
  1736.      plt_exec(ptr);
  1737.      ptr=ptr->next;
  1738.  
  1739.   } while ( ptr !=list->d_list->next );
  1740.  
  1741.   /* end of segment */
  1742.   plt_exec(&closeinstr);
  1743.  
  1744. } /* plt_draw_seg */
  1745.  
  1746. /*****************************************************************************
  1747.  
  1748.     plt_xform will transform a coordinate of the current segment to world
  1749.   coordinate and adjust its significance.
  1750.  
  1751.   Input
  1752.     fx, fy - coordinate in coordinate system of current segment
  1753.  
  1754.   Output
  1755.     ix, iy - world coordinate
  1756.  
  1757. *****************************************************************************/
  1758.  
  1759. plt_xform(fx,fy,ix,iy)
  1760. float fx, fy;
  1761. int *ix, *iy;
  1762. {
  1763.   float x, y;
  1764.  
  1765.   /* transform coordinate */
  1766.   x = cosa * fx * curr_attr.sx - sina * fy * curr_attr.sy + curr_attr.tx;
  1767.   y = sina * fx * curr_attr.sx + cosa * fy * curr_attr.sy + curr_attr.ty;
  1768.  
  1769.   /* adjust significance */
  1770.   *ix = (int)(x * SCALE + 0.5);
  1771.   *iy = (int)(y * SCALE + 0.5);
  1772.  
  1773. } /* plt_xform */
  1774.  
  1775. /*****************************************************************************
  1776.  
  1777.     plt_sim_ellipse will simulate the drawing of an ellipse by dividing
  1778.   the ellipse into a number of segments and draw each segment with an
  1779.   arc.  This is necessary because plot(3) cannot draw ellipse.
  1780.  
  1781.     Coordinates of points on the ellipse are determined by transformation
  1782.   of points on a circle at (0,0) with radius 1.
  1783.  
  1784.   Input
  1785.     xcur, ycur - current world coordinate
  1786.     a,b - half of width and height of ellipse
  1787.  
  1788. *****************************************************************************/
  1789.  
  1790. plt_sim_ellipse(xcur, ycur, a, b)
  1791. int xcur, ycur;
  1792. float a, b;
  1793. {
  1794.  
  1795. #define PLT_CIRINT 20 /* number of segments to divide into */
  1796. #define PLT_CIRSIZE PLT_CIRINT*2+1 /* size of array necessary */
  1797.  
  1798.   static int plt_mdl_make = 0;
  1799.   static float plt_cir_x[PLT_CIRSIZE];
  1800.   static float plt_cir_y[PLT_CIRSIZE];
  1801.   extern float ge_radius2(); /* from misc.c */
  1802.   float radius; /* radius of arc */
  1803.   int x1, y1, x2, y2, x3, y3;
  1804.   float x,y;
  1805.   int i;
  1806.  
  1807.   /* put the coordinates of points on a circle with center at (0,0)
  1808.      and radius 1 in plt_cir_x and plt_cir_y at the first time */
  1809.   if ( ! plt_mdl_make ) {
  1810.     int count;
  1811.     float intv;
  1812.  
  1813.     intv = PI / PLT_CIRINT;
  1814.     for (count=0; count < PLT_CIRSIZE; count ++ ) {
  1815.       plt_cir_x[count]=cos(intv*count);
  1816.       plt_cir_y[count]=sin(intv*count);
  1817.     }
  1818.     plt_mdl_make = 1;
  1819.  
  1820.   } /* if */
  1821.  
  1822.   /* determine the world coordinate of the first point */
  1823.   plt_xform(plt_cir_x[0]*a, plt_cir_y[0]*b, &x3, &y3);
  1824.  
  1825.   /* draw the arcs */
  1826.   for ( i=0; i<PLT_CIRSIZE-1; i+=2 ) {
  1827.  
  1828.     /* make the end point of the last arc the start point */
  1829.     x1=x3; y1=y3;
  1830.  
  1831.     /* determine the world coordinate of the mid point and the end point */
  1832.     plt_xform(plt_cir_x[i+1]*a,plt_cir_y[i+1]*b, &x2, &y2);
  1833.     plt_xform(plt_cir_x[i+2]*a,plt_cir_y[i+2]*b, &x3, &y3);
  1834.  
  1835.     /* determine the center of the arc passing the start point, midpoint and
  1836.        end point */
  1837.     (void) ge_radius2((float)x1,(float)y1,(float)x2,(float)y2,
  1838.                       (float)x3,(float)y3,&x,&y);
  1839.  
  1840.     /* draw the arc */
  1841.     arc((int)(x+xcur-curr_attr.tx*SCALE),(int)(y+ycur-curr_attr.ty*SCALE),
  1842.         (int)(x1+xcur-curr_attr.tx*SCALE),(int)(y1+ycur-curr_attr.ty*SCALE),
  1843.         (int)(x3+xcur-curr_attr.tx*SCALE),(int)(y3+ycur-curr_attr.ty*SCALE));
  1844.  
  1845.   } /* for */
  1846.  
  1847. } /* plt_sim_ellipse */
  1848.  
  1849. /*****************************************************************************
  1850.  
  1851.     plt_sim_arc will simulate an arc which is not a real arc after
  1852.   transformation of the current segment with a number of small arcs.
  1853.  
  1854.   Input
  1855.     cx, cy - center of arc in world coordinate
  1856.     ang1 - start angle in radian, 0 <= ang1 <= 2*PI
  1857.     ang2 - end angle in radian, 0 <= ang2 <= 2*PI
  1858.     arcradius - radius of arc 
  1859.  
  1860. *****************************************************************************/
  1861.  
  1862. plt_sim_arc(cx,cy,ang1,ang2,arcradius)
  1863. int cx,cy;
  1864. float ang1,ang2,arcradius;
  1865. {
  1866.   float intv, radius;
  1867.   extern float ge_radius2();
  1868.   int count;
  1869.   int x1,y1,x2,y2,x3,y3; /* start, mid and end point of small arc */
  1870.   float ang,x,y;
  1871.  
  1872.   intv = PI / PLT_CIRINT;
  1873.  
  1874.   /* ensure ang1 is less than ang2 */
  1875.   if ( ang1 > ang2 )
  1876.   ang1 -= 2*PI;
  1877.  
  1878.   /* determine how many small arcs it will be divided into,
  1879.      the minimum is 3 */
  1880.   count = (int)((ang2-ang1)/(2*intv));
  1881.   if ( count < 3 ) count = 3;
  1882.  
  1883.   intv = (ang2-ang1)/(count*2);
  1884.  
  1885.   /* transform the first point */
  1886.   plt_xform(cos(ang1)*arcradius,sin(ang1)*arcradius,&x3,&y3);
  1887.  
  1888.   /* draw the arcs */
  1889.   for ( ang = ang1; ang< (ang2-2*intv); ang += 2*intv) {
  1890.  
  1891.     /* make end point of last arc the start point */
  1892.     x1=x3; y1=y3;
  1893.  
  1894.     /* transform mid point */
  1895.     plt_xform(cos(ang+intv)*arcradius,
  1896.               sin(ang+intv)*arcradius, &x2, &y2);
  1897.  
  1898.     /* transform end point */
  1899.     plt_xform(cos(ang+2*intv)*arcradius,
  1900.               sin(ang+2*intv)*arcradius, &x3, &y3);
  1901.  
  1902.     /* determine radius of arc */
  1903.     (void)ge_radius2((float)x1,(float)y1,(float)x2,(float)y2,
  1904.                      (float)x3,(float)y3,&x,&y);
  1905.  
  1906.     /* draw small arc */
  1907.     arc((int)(x+cx-curr_attr.tx*SCALE+0.5),
  1908.         (int)(y+cy-curr_attr.ty*SCALE+0.5),
  1909.         (int)(x1+cx-curr_attr.tx*SCALE),
  1910.         (int)(y1+cy-curr_attr.ty*SCALE),
  1911.         (int)(x3+cx-curr_attr.tx*SCALE),
  1912.         (int)(y3+cy-curr_attr.ty*SCALE));
  1913.  
  1914.   } /* for */
  1915.  
  1916. }  /* plt_sim_arc */
  1917.  
  1918. /*****************************************************************************
  1919.  
  1920.     plt_exec will execute an instruction.  It call routines in plot(3) to
  1921.   actually do the drawing.
  1922.  
  1923.   Input
  1924.     ptr - pointer to instruction
  1925.  
  1926. *****************************************************************************/
  1927.  
  1928. plt_exec(ptr)
  1929. struct list_item *ptr;
  1930. {
  1931.     static int xbuff[512], ybuff[512];
  1932.     static int lastinstr=0;
  1933.     static int n=0; /* number of points in polygon/polyline */
  1934.     static int xcur, ycur; /* current point */
  1935.     int i;
  1936.  
  1937.  /* check whether the list of points for polygon/polyline end */
  1938.  if ( lastinstr && ptr->instr !=GE_CONT ) {
  1939.    switch ( lastinstr ) {
  1940.      case GE_POLYLINE:
  1941.        /* draw polyline */
  1942.        move (xcur, ycur);
  1943.        for (i=0; i<n; i++) { 
  1944.          cont(xbuff[i], ybuff[i]);
  1945.        }
  1946.        xcur=xbuff[n-1];
  1947.        ycur=ybuff[n-1];
  1948.        break;
  1949.      
  1950.      case GE_POLYGON:
  1951.        /* draw polygon */
  1952.        move(xbuff[0],ybuff[0]);
  1953.        for ( i=1; i<n; i++ ) {
  1954.          cont(xbuff[i], ybuff[i]);
  1955.        }
  1956.        cont(xbuff[0],ybuff[0]);
  1957.        xcur=xbuff[0];
  1958.        ycur=ybuff[0];
  1959.        break;
  1960.      
  1961.     } /* switch */
  1962.     lastinstr = n = 0; 
  1963.   } /* if */
  1964.  
  1965.   switch (ptr->instr) {
  1966.  
  1967.     case GE_MOVE:
  1968.       plt_xform(ptr->x, ptr->y, &xcur, &ycur);
  1969.       move(xcur, ycur);
  1970.       break;
  1971.    
  1972.     case GE_LINE:
  1973.       {
  1974.         int tmpx, tmpy;
  1975.         plt_xform(ptr->x, ptr->y, &tmpx, &tmpy);
  1976.         line(xcur, ycur, tmpx, tmpy);
  1977.         xcur=tmpx;
  1978.         ycur=tmpy;
  1979.       }
  1980.       break;
  1981.       
  1982.     case GE_CIRCLE:
  1983.       if ( curr_attr.sx == curr_attr.sy ) {
  1984.         /* draw it as a circle if it is still a circle after
  1985.            transformation of current segment */
  1986.         int radius;
  1987.  
  1988.         radius = (int)(ptr->x*SCALE+0.5);
  1989.         circle(xcur,ycur,radius);
  1990.       }
  1991.       else {
  1992.         plt_sim_ellipse(xcur,ycur,ptr->x,ptr->x);
  1993.       }
  1994.       break;   
  1995.  
  1996.     case GE_ELLIPSE:
  1997.       /* draw ellipse */
  1998.       plt_sim_ellipse(xcur,ycur,ptr->x,ptr->y);
  1999.       break;
  2000.  
  2001.     case GE_ARC:
  2002.     case GE_ARCEXT:
  2003.       {
  2004.         static float ang1, ang2;
  2005.  
  2006.         if ( ptr->instr == GE_ARC ) {
  2007.           /* save angles of arc */
  2008.           ang1 = ptr->x;
  2009.           ang2 = ptr->y;
  2010.         } /* GE_ARC */
  2011.  
  2012.         else {
  2013.  
  2014.           if ( curr_attr.sx == curr_attr.sy ) {
  2015.             /* draw arc as one arc if it is a real arc after
  2016.                transformation of current segment */
  2017.             int x1,y1,x2,y2;
  2018.  
  2019.             /* transform start point and end point of arc */
  2020.             plt_xform(cos(ang1)*ptr->x,sin(ang1)*ptr->x,&x1,&y1);
  2021.             plt_xform(cos(ang2)*ptr->x,sin(ang2)*ptr->x,&x2,&y2);
  2022.  
  2023.             /* draw arc */
  2024.             arc(xcur,ycur,
  2025.                 (int)(x1+xcur-curr_attr.tx*SCALE),
  2026.                 (int)(y1+ycur-curr_attr.ty*SCALE),
  2027.                 (int)(x2+xcur-curr_attr.tx*SCALE),
  2028.                 (int)(y2+ycur-curr_attr.ty*SCALE));
  2029.           }
  2030.           else {
  2031.             /* draw 'arc' with a number of small arcs */
  2032.             plt_sim_arc(xcur,ycur,ang1,ang2,ptr->x);
  2033.           }
  2034.  
  2035.         } /* GE_ARCEXT */
  2036.  
  2037.       } /* case GE_ARC, GE_ARCEXT */
  2038.       break;
  2039.  
  2040.     case GE_POLYLINE:
  2041.     case GE_POLYGON:
  2042.       lastinstr=ptr->instr;
  2043.    
  2044.     case GE_CONT:
  2045.       plt_xform(ptr->x, ptr->y, &xbuff[n], &ybuff[n]);
  2046.       n++;
  2047.       break;
  2048.  
  2049.     case GE_SETTYPELINE:
  2050.       /* change the line style */
  2051.       linemod(plt_linestyle[(int)ptr->x]);
  2052.       break;
  2053.  
  2054.     case GE_TEXT:
  2055.       /* draw text */
  2056.       label((char *)((int)ptr->x));
  2057.       break;
  2058.  
  2059.     /* ignore these instructions */
  2060.     case GE_SETCOLOR:
  2061.     case GE_SETFONT:
  2062.     case GE_SETCHARSIZE:
  2063.     case GE_SETLINEWIDTH:
  2064.     case GE_FILL:
  2065.     case GE_CLOSE:
  2066.       break;
  2067.  
  2068.     /* check that all instructions are handled properly */
  2069.     default:
  2070.       fprintf(stderr,
  2071.               "Internal Error-Action for instruction %d missing.\n",
  2072.               ptr->instr);
  2073.       break;
  2074.  
  2075.   } /* switch */
  2076.            
  2077. } /* plt_exec */
  2078. @//E*O*F plot.c//
  2079. chmod u=r,g=r,o=r plot.c
  2080.  
  2081. echo Inspecting for damage in transit...
  2082. temp=/tmp/shar$$; dtemp=/tmp/.shar$$
  2083. trap "rm -f $temp $dtemp; exit" 0 1 2 3 15
  2084. cat > $temp <<\!!!
  2085.      314    1039    8695 display.c
  2086.      689    1901   18053 ps.c
  2087.      579    1887   16700 pic.c
  2088.      464    1461   12850 plot.c
  2089.     2046    6288   56298 total
  2090. !!!
  2091. wc  display.c ps.c pic.c plot.c | sed 's=[^ ]*/==' | diff -b $temp - >$dtemp
  2092. if [ -s $dtemp ]
  2093. then echo "Ouch [diff of wc output]:" ; cat $dtemp
  2094. else echo "No problems found."
  2095. fi
  2096. exit 0
  2097.  
  2098.